from flask import Flask, request, jsonify
from flask_cors import CORS
import jwt
import datetime
import re
from tools.myjwt import JWTManager
from tools.myredis import redis_manager
from tools.db import init_db

app = Flask(__name__)
CORS(app, 
     origins=['http://localhost:3000', 'http://127.0.0.1:3000'],
     methods=['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],
     allow_headers=['Content-Type', 'Authorization', 'X-Requested-With'],
     supports_credentials=True)

# 初始化数据库
db = init_db(app, use_mysql=True)

# 注册蓝图
from views.users import users_blueprint
from views.views import views_bp
from views.menu_api import menu_bp
from views.business_api import business_bp
app.register_blueprint(users_blueprint, url_prefix='/api')
app.register_blueprint(views_bp, url_prefix='/api')
app.register_blueprint(menu_bp, url_prefix='/api')
app.register_blueprint(business_bp, url_prefix='/api')

# 白名单URLs - 不需要token验证的路径
WHITELIST_URLS = [
    '/api/user/login',
    '/api/user/refresh',  # 刷新token接口不需要Authorization头
    '/api/health',
    '/api/status',
    '/api/menus',  # 菜单接口不需要认证
    '/api/roles',  # 角色接口不需要认证
    '/api/users',  # 用户接口不需要认证
    '/api/customers',  # 客户接口不需要认证
    '/api/products',   # 商品接口不需要认证
    '/api/suppliers',  # 供应商接口不需要认证
    '/api/sales',      # 销售接口不需要认证
    '/api/inventory'   # 库存接口不需要认证
]

# 权限配置i
PERMISSION_CONFIG = {
    'admin': {
        'paths': ['/api/admin/*', '/api/orders/*', '/api/user/*'],
        'methods': ['GET', 'POST', 'PUT', 'DELETE']
    },
    'user': {
        'paths': ['/api/user/userinfo', '/api/orders/*'],
        'methods': ['GET', 'POST']
    }
}

def is_whitelisted(path):
    """检查路径是否在白名单中"""
    return any(path.startswith(url.rstrip('*')) for url in WHITELIST_URLS)

def has_permission(user_id, path, method):
    """检查用户权限"""
    user_role = 'admin' if user_id == 1 else 'user'  # 简化角色判断
    user_permissions = get_user_permissions(user_id)
    
    allowed_paths = user_permissions.get('paths', [])
    allowed_methods = user_permissions.get('methods', [])
    
    # 检查路径权限
    path_allowed = any(path.startswith(p.rstrip('*')) for p in allowed_paths)
    method_allowed = method in allowed_methods
    
    return path_allowed and method_allowed

def get_user_permissions(user_id):
    """获取用户权限配置"""
    user_role = 'admin' if user_id == 1 else 'user'  # 简化角色判断
    return PERMISSION_CONFIG.get(user_role, {})

@app.before_request
def before_request():
    # 处理OPTIONS预检请求
    if request.method == 'OPTIONS':
        return '', 200
    """
    请求前中间件 - 完整的token验证流程
    
    验证步骤：
    1. 检查是否在白名单中
    2. 检查是否携带token
    3. 检查token格式是否正确
    4. 检查token是否被修改
    5. 检查token是否过期
    6. 检查token是否已退出（黑名单）
    7. 检查用户权限
    """
    current_path = request.path
    current_url = request.url
    request_method = request.method
    
    print(f"[AUTH] 请求路径: {current_path}")
    print(f"[AUTH] 请求方法: {request_method}")
    print(f"[AUTH] 完整URL: {current_url}")
    
    if is_whitelisted(current_path):
        print(f"[AUTH] 路径 {current_path} 在白名单中，跳过验证")
        return None
    
    print(f"[AUTH] 路径 {current_path} 不在白名单中，开始token验证")
    
    auth_header = request.headers.get('Authorization')
    if not auth_header:
        print("[AUTH] 错误: 缺少Authorization头")
        return jsonify({
            "code": 401,
            "message": "缺少认证令牌，请先登录",
            "error_type": "missing_token"
        }), 401
    
    print(f"[AUTH] 找到Authorization头: {auth_header[:20]}...")
    
    try:
        if not auth_header.startswith('Bearer '):
            print("[AUTH] 错误: token格式不正确，应该以'Bearer '开头")
            return jsonify({
                "code": 401,
                "message": "令牌格式错误，应该以'Bearer '开头",
                "error_type": "invalid_format"
            }), 401
        
        token = auth_header.split(' ')[1]
        if not token:
            print("[AUTH] 错误: token为空")
            return jsonify({
                "code": 401,
                "message": "令牌不能为空",
                "error_type": "empty_token"
            }), 401
            
    except IndexError:
        print("[AUTH] 错误: token解析失败")
        return jsonify({
            "code": 401,
            "message": "令牌格式错误，无法解析",
            "error_type": "parse_error"
        }), 401
    
    print(f"[AUTH] 提取到token: {token[:20]}...")
    
    # 检查token是否在黑名单中
    if redis_manager.is_token_blacklisted(token):
        print("[AUTH] 错误: token在黑名单中（用户已退出登录）")
        return jsonify({
            "code": 401,
            "message": "令牌已失效，用户已退出登录，请重新登录",
            "error_type": "token_blacklisted"
        }), 401
    
    print("[AUTH] token不在黑名单中")
    
    payload = JWTManager.decode_token(token)
    if 'error' in payload:
        error_msg = payload['error']
        print(f"[AUTH] 错误: token验证失败 - {error_msg}")
        
        if 'expired' in error_msg.lower() or 'exp' in error_msg.lower():
            return jsonify({
                "code": 401,
                "message": "令牌已过期，请刷新令牌或重新登录",
                "error_type": "token_expired"
            }), 401
        elif 'invalid' in error_msg.lower():
            return jsonify({
                "code": 401,
                "message": "令牌无效或已被修改，请重新登录",
                "error_type": "token_invalid"
            }), 401
        else:
            return jsonify({
                "code": 401,
                "message": f"令牌验证失败: {error_msg}",
                "error_type": "token_verification_failed"
            }), 401
    
    print("[AUTH] token验证成功")
    
    token_type = payload.get('token_type')
    if token_type != 'access':
        print(f"[AUTH] 错误: 错误的token类型 - {token_type}")
        return jsonify({
            "code": 401,
            "message": "令牌类型错误，请使用访问令牌",
            "error_type": "wrong_token_type"
        }), 401
    
    print(f"[AUTH] token类型正确: {token_type}")
    
    user_id = payload.get('user_id')
    username = payload.get('username')
    
    if not user_id or not username:
        print("[AUTH] 错误: token中缺少用户信息")
        return jsonify({
            "code": 401,
            "message": "令牌中缺少用户信息",
            "error_type": "missing_user_info"
        }), 401
    
    print(f"[AUTH] 用户信息: ID={user_id}, 用户名={username}")
    
    if not has_permission(user_id, current_path, request_method):
        print(f"[AUTH] 错误: 用户 {username} 没有权限访问 {current_path}")
        return jsonify({
            "code": 403,
            "message": "权限不足，无法访问该资源",
            "error_type": "insufficient_permission"
        }), 403
    
    print(f"[AUTH] 权限检查通过")
    
    request.current_user = payload
    print(f"[AUTH] 用户 {username} 验证成功，允许访问")
    
    return None

# 用户相关路由
@app.route('/api/user/login', methods=['POST'])
def login():
    """
    用户登录接口
    
    请求参数:
        username (str): 用户名
        password (str): 密码
    """
    try:
        print(f"[LOGIN] 收到登录请求")
        # 1. 获取POST数据
        data = request.get_json()
        print(f"[LOGIN] 请求数据: {data}")
        if not data:
            print(f"[LOGIN] 错误: 请求数据为空")
            return jsonify({
                "code": 400,
                "message": "请求数据不能为空"
            }), 400
        
        username = data.get('username')
        password = data.get('password')
        print(f"[LOGIN] 用户名: {username}, 密码: {password[:3]}***")
        
        # 2. 数据验证
        if not username or not password:
            print(f"[LOGIN] 错误: 用户名或密码为空")
            return jsonify({
                "code": 400,
                "message": "用户名和密码不能为空"
            }), 400
        
        # 简单的用户名格式验证
        if not re.match(r'^[a-zA-Z0-9_]{3,20}$', username):
            return jsonify({
                "code": 400,
                "message": "用户名格式不正确，应为3-20位字母、数字或下划线"
            }), 400
        
        # 简单的密码长度验证
        if len(password) < 6:
            return jsonify({
                "code": 400,
                "message": "密码长度不能少于6位"
            }), 400
        
        # 3. 模拟用户验证（实际项目中应该查询数据库）
        if username == 'admin' and password == '123456':
            print(f"[LOGIN] 用户验证成功")
            # 4. 生成JWT令牌
            user_id = 1
            access_token = JWTManager.generate_access_token(user_id, username)
            refresh_token = JWTManager.generate_refresh_token(user_id, username)
            print(f"[LOGIN] 生成token成功")
            
            # 5. 将refresh_token存储到Redis中
            redis_manager.store_refresh_token(user_id, refresh_token, 3600)  # 1小时过期
            print(f"[LOGIN] 存储refresh_token到Redis: {refresh_token[:20]}...")
            
            # 6. 返回登录成功响应
            return jsonify({
                "code": 200,
                "message": "登录成功",
                "data": {
                    "access_token": access_token,
                    "refresh_token": refresh_token,
                    "token_type": "Bearer",
                    "expires_in": 1800,  # 30分钟，单位：秒
                    "user_info": {
                        "user_id": user_id,
                        "username": username
                    }
                }
            }), 200
        else:
            print(f"[LOGIN] 用户验证失败: username={username}, password={password[:3]}***")
            return jsonify({
                "code": 401,
                "message": "用户名或密码错误"
            }), 401
            
    except Exception as e:
        return jsonify({
            "code": 500,
            "message": f"服务器内部错误: {str(e)}"
        }), 500

@app.route('/api/user/logout', methods=['POST'])
def logout():
    """
    用户退出登录接口
    
    请求参数:
        access_token (str): 访问令牌
    """
    try:
        data = request.get_json()
        if not data:
            return jsonify({
                "code": 400,
                "message": "请求数据不能为空"
            }), 400
        
        access_token = data.get('access_token')
        if not access_token:
            return jsonify({
                "code": 400,
                "message": "缺少访问令牌"
            }), 400
        # 解析token获取用户信息
        payload = JWTManager.decode_token(access_token)
        if 'error' in payload:
            return jsonify({
                "code": 401,
                "message": payload['error']
            }), 401
        
        user_id = payload.get('user_id')
        
        # 将access_token添加到黑名单
        redis_manager.add_token_to_blacklist(access_token, 1800)  # 30分钟过期
        
        # 删除用户的refresh_token
        redis_manager.delete_refresh_token(user_id)
        
        return jsonify({
            "code": 200,
            "message": "退出登录成功"
        }), 200
        
    except Exception as e:
        return jsonify({
            "code": 500,
            "message": f"服务器内部错误: {str(e)}"
        }), 500

@app.route('/api/user/refresh', methods=['POST'])
def refresh_token():
    """
    刷新token接口
    
    请求参数:
        refresh_token (str): 刷新令牌
    """
    try:
        print(f"[REFRESH] 收到刷新Token请求")
        data = request.get_json()
        print(f"[REFRESH] 请求数据: {data}")
        if not data:
            print(f"[REFRESH] 错误: 请求数据为空")
            return jsonify({
                "code": 400,
                "message": "请求数据不能为空"
            }), 400
        
        refresh_token = data.get('refresh_token')
        print(f"[REFRESH] 获取到的refresh_token: {refresh_token[:20] if refresh_token else 'None'}...")
        if not refresh_token:
            print(f"[REFRESH] 错误: 缺少刷新令牌")
            return jsonify({
                "code": 400,
                "message": "缺少刷新令牌"
            }), 400
        
        payload = JWTManager.decode_token(refresh_token)
        if 'error' in payload:
            return jsonify({
                "code": 401,
                "message": payload['error']
            }), 401
        
        if payload.get('token_type') != 'refresh':
            return jsonify({
                "code": 401,
                "message": "令牌类型错误"
            }), 401
        
        user_id = payload.get('user_id')
        username = payload.get('username')
        
        # 验证refresh_token是否在Redis中
        stored_refresh_token = redis_manager.get_refresh_token(user_id)
        print(f"[REFRESH] 用户ID: {user_id}")
        print(f"[REFRESH] 请求的refresh_token: {refresh_token[:20]}...")
        print(f"[REFRESH] Redis中存储的token: {stored_refresh_token[:20] if stored_refresh_token else 'None'}...")
        
        # 如果Redis中没有存储的token，但JWT token有效，则允许刷新（兼容性处理）
        if not stored_refresh_token:
            print(f"[REFRESH] Redis中没有存储的token，但JWT有效，允许刷新")
        elif stored_refresh_token != refresh_token:
            print(f"[REFRESH] 验证失败: stored={bool(stored_refresh_token)}, match={stored_refresh_token == refresh_token}")
            return jsonify({
                "code": 401,
                "message": "刷新令牌无效或已使用"
            }), 401
        
        # 生成新的token
        new_access_token = JWTManager.generate_access_token(user_id, username)
        new_refresh_token = JWTManager.generate_refresh_token(user_id, username)
        
        # 更新Redis中的refresh_token
        redis_manager.store_refresh_token(user_id, new_refresh_token, 3600)
        
        # 将旧的refresh_token加入黑名单
        redis_manager.add_token_to_blacklist(refresh_token, 3600)
        
        return jsonify({
            "code": 200,
            "message": "令牌刷新成功",
            "data": {
                "access_token": new_access_token,
                "refresh_token": new_refresh_token,
                "token_type": "Bearer",
                "expires_in": 1800,
                "user_info": {
                    "user_id": user_id,
                    "username": username
                }
            }
        }), 200
        
    except Exception as e:
        return jsonify({
            "code": 500,
            "message": f"服务器内部错误: {str(e)}"
        }), 500

@app.route('/api/user/userinfo', methods=['GET'])
def userinfo():
    """
    获取用户信息接口
    """
    try:
        user_info = request.current_user
        return jsonify({
            "code": 200,
            "message": "获取用户信息成功",
            "data": {
                "user_id": user_info.get('user_id'),
                "username": user_info.get('username'),
                "login_time": user_info.get('login_time')
            }
        }), 200
        
    except Exception as e:
        return jsonify({
            "code": 500,
            "message": f"服务器内部错误: {str(e)}"
        }), 500

# 测试接口
@app.route('/api/health', methods=['GET'])
def health():
    """健康检查接口"""
    return jsonify({
        "code": 200,
        "message": "服务正常",
        "data": {
            "status": "healthy",
            "timestamp": datetime.datetime.utcnow().isoformat()
        }
    }), 200

@app.route('/api/status', methods=['GET'])
def status():
    """状态检查接口"""
    return jsonify({
        "code": 200,
        "message": "系统状态正常",
        "data": {
            "redis_connected": redis_manager.redis_client is not None,
            "timestamp": datetime.datetime.utcnow().isoformat()
        }
    }), 200

@app.route('/api/admin/users', methods=['GET'])
def admin_users():
    """管理员用户列表接口"""
    return jsonify({
        "code": 200,
        "message": "获取用户列表成功",
        "data": {
            "users": [
                {"id": 1, "username": "admin", "role": "admin"},
                {"id": 2, "username": "user1", "role": "user"}
            ]
        }
    }), 200

@app.route('/api/orders', methods=['GET'])
def orders():
    """订单列表接口"""
    return jsonify({
        "code": 200,
        "message": "获取订单列表成功",
        "data": {
            "orders": [
                {"id": 1, "title": "订单1", "status": "已完成"},
                {"id": 2, "title": "订单2", "status": "进行中"}
            ]
        }
    }), 200


if __name__ == '__main__':
    print("启动Flask应用 (带Redis黑名单功能)")
    print("功能特性:")
    print("   - JWT认证")
    print("   - Redis黑名单")
    print("   - Token刷新")
    print("   - 权限控制")
    print("   - 白名单机制")
    print("访问地址: http://localhost:5000")
    print("健康检查: http://localhost:5000/api/health")
    print("状态检查: http://localhost:5000/api/status")
    app.run(debug=True, host='0.0.0.0', port=5000)
